package com.codeborne.selenide.clearwithshortcut;

import com.codeborne.selenide.Driver;
import com.codeborne.selenide.commands.Clear;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.openqa.selenium.Keys.DELETE;
import static org.slf4j.LoggerFactory.getLogger;

/**
 * Clean the input field value.
 * <br>
 * <p>
 *  The standard Selenium method {@link WebElement#clear()} does not help in case of
 *  "tricky" inputs generated by Vue.js, React and other fancy frameworks.
 * </p>
 * <br>
 * <p>
 *  That's why we need to clear the field value by emulating real user actions:
 * </p>
 * <ol>
 *   <li>Select the whole text</li>
 *   <li>press "Delete"</li>
 * </ol>
 */
public class ClearWithShortcut extends Clear {
  private static final Logger log = LoggerFactory.getLogger(ClearWithShortcut.class);

  /**
   * Clear the input content without triggering "change" and "blur" events
   */
  @Override
  protected void clear(Driver driver, WebElement input) {
    input.clear();
    clearWithShortcut(driver, input);
  }

  protected void clearWithShortcut(Driver driver, WebElement input) {
    Platform platform = getPlatform(driver);
    if (!platform.isUnknown()) {
      try {
        CharSequence modifier = platform.modifierKey();
        driver.actions()
          .sendKeys(input, "0")
          .keyDown(modifier).sendKeys("a").keyUp(modifier).sendKeys(DELETE)
          .perform();
      }
      catch (WebDriverException failedToPressKeys) {
        log.error("Failed to clear the input with shortcut", failedToPressKeys);
      }
    }
  }

  protected Platform getPlatform(Driver driver) {
    if (!driver.supportsJavascript()) {
      return Platform.UNKNOWN;
    }
    try {
      String platform = driver.executeJavaScript("return navigator.platform");
      if (platform == null || platform.trim().isEmpty()) {
        getLogger(getClass()).warn("Cannot detect platform: navigator.platform returned \"{}\"", platform);
      }
      return new Platform(platform);
    }
    catch (WebDriverException cannotExecuteJavascript) {
      getLogger(getClass()).debug("Cannot get navigator.platform", cannotExecuteJavascript);
      return Platform.UNKNOWN;
    }
  }
}
